﻿using STHPMS1.BLL.B_Core;
using STHPMS1.BLL.B_Serv;
using STHPMS1.Common.C_Entity.Stmpms1;
using STHPMS1.Common.C_Enum;
using STHPMS1.ICore.I_BLL.Bus;
using STHPMS1.ICore.I_DAL;
using STHPMS1.ICore.I_Entity.Info;
using STHPMS1.ICore.I_Entity.Stmpms1;
using STHPMS1.ICore.I_Serv;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq.Expressions;
using STHPMS1.Common.C_Extension;
using System.Linq;
using EmitMapper;
using STHPMS1.ICore;

namespace STHPMS1.BLL.B_Bus
{
    public class Dm_ModelgroupBus : BllBase, IDm_ModelgroupBill
    {
        public void Save<T>(T entity)
            where T : class ,IDm_Modelgroup
        {
            if (this.Scene.Dal.Sthpms1.Update(entity) == 0)
            {
                this.Scene.Dal.Sthpms1.Insert(entity);
            }
        }

        public void Remove(IDm_Modelgroup entity)
        {
            this.Scene.Dal.Sthpms1.Delete(entity);
        }

        public IEnumerable<T> Get<T>(Expression<Func<T, bool>> predicate, IPagingInfo info)
            where T : class, IDm_Modelgroup
        {
            return this.Scene.Dal.Sthpms1.Select<T>(predicate, info);
        }
        public DataTable GetAllModelGroups<T>(string predicate, IPagingInfo info, bool? check = null)
            where T : class, IDm_Modelgroup
        {
            DataTable dt = this.Scene.Dal.Sthpms1.Dm_Modelgroup.GetAllModelGroups(predicate);
            int currentPageIndex = info.PageIndex;
            int pageSize = info.PageSize;

            if (check==true)
            {
                List<DataRow> drs=new List<DataRow>();
                foreach (DataRow item in dt.Rows)
                {
                    if (item["LASTYEAR"]==item["PERFYEAR"])
                    {
                        drs.Add(item);
                    }
                }

                foreach (var dr in drs)
                {
                    dr.Delete();
                }

                dt.AcceptChanges();
            }
           

            DataTable newdt = dt.Clone();


            int rowbegin = currentPageIndex * pageSize;//当前页的第一条数据在dt中的位置
            int rowend = (currentPageIndex + 1) * pageSize;//当前页的最后一条数据在dt中的位置

            if (rowbegin >= dt.Rows.Count)
            {
                return newdt;
            }

            if (rowend > dt.Rows.Count)
            {
                rowend = dt.Rows.Count;
            }

            DataView dv = dt.DefaultView;
            for (int i = rowbegin; i <= rowend - 1; i++)
            {
                newdt.ImportRow(dv[i].Row);
            }

            info.TotalRecords = dt.Rows.Count;

            return newdt;
        }


        private List<Dm_Modelgroup> _modelList;
        private List<Dm_Esalage> _esalageList;
        public void LoadData()
        {
            _modelList = this.Scene.Dal.Sthpms1.Select<Dm_Modelgroup>();
            _esalageList = this.Scene.Dal.Sthpms1.Select<Dm_Esalage>();
        }
        
        public void UnloadData()
        {
            _modelList = null;
            _esalageList = null;
        }


        public IModelCalculateService GetModelServ(IDn_Divi_Result result)
        {
            ISthpms1Dao dao=this.Scene.Dal.Sthpms1;
            IDm_Modelgroup model = null;
            if (_modelList == null)
                model = dao.Dm_Modelgroup.GetModelById(result.ModelGroup_PCI);
            else
                model = _modelList.FirstOrDefault(p => p.Modelgroup_Id == result.ModelGroup_PCI);

            if (model == null) throw new Exception("模型信息不存在-" + result.ModelGroup_PCI);

            return ModelCalculateService.CreateServiceByModel(model);
        }

        public double GetPciByModel(IDn_Divi_Result result, int year)
        {
            IModelCalculateService serv = this.GetModelServ(result);
            return serv.CalculateY(GetEaslByModel(result,year));
        }

        public double GetEaslByModel(IDn_Divi_Result result, int year)
        {
            if (result == null) throw new Exception("决策路段信息不能为空!");
            int age = year - result.BeginDate.Value.Year;
            if (age < 0) throw new Exception("指定年份必段大于通车年份-" + year);
            double? esal = null;
            if (_esalageList == null)
                esal = this.Scene.Dal.Sthpms1.Dm_Modelgroup.GetSegEsalByYear(result.Segid, age);
            else
            {
                Dm_Esalage dm_esalage=_esalageList.FirstOrDefault(p=>p.Segid==result.Segid && p.Perfyear==age);
                if (dm_esalage != null)
                    esal = dm_esalage.Easl;
            }

            if (esal == null) throw new Exception("该基础路段的路龄对应的累计轴载还没有计算-" + result.Segid + ":" + age);
            return (double)esal;
        }


        public List<Object> GetModelGraphic(string modelId)
        {
            ISthpms1Dao dao=this.Scene.Dal.Sthpms1;
            Dm_Modelgroup model = dao.SingleById<Dm_Modelgroup>(modelId);
            if (model == null) throw new Exception("该模型不存在-"+modelId);

            if(model.Modelmode_Dictid!=ModelFormEnum.M821.GetEnumValue())throw new Exception("该模型形式的模型还没有实现-"+modelId);

            var easlageList = dao.Dm_Trafaxle.GetEsalageByModel<Dm_Esalage>(modelId);

            var perfList = dao.Select<Dm_Histperf>(p => p.Modelgroup_Id == modelId);


            IModelCalculateService modelServ = ModelCalculateService.CreateServiceByModel(model);

            List<Object> series = new List<object>();
            List<double[]> data = new List<double[]>();

            data.Add(new double[2] {0, modelServ.CalculateY(0) });
            data.Add(new double[2] {modelServ.CalculateX(0), 0 });

            foreach (var item in easlageList.GroupBy(k=>k.Easl))
	        {
                data.Add(new double[2] { item.Key.ToD(), modelServ.CalculateY(item.Key.ToD()) });
	        }

            data.Sort(new Comparison<double[]>((a,b)=>{
                if (a[0] < b[0])
                    return -1;
                if (a[0] > b[0])
                    return 1;
                return 0;
            }));

            series.Add(
                 new
                 {
                     type = "line",
                     name = GetModelName(model),
                     marker = new { enabled = false },
                     states = new { hover = new { lineWidth = 0 } },
                     enableMouseTracking = false,
                     data = data.ToArray()
                 }
            );


            foreach (var esalItem in data)
            {
                List<double[]> yList = new List<double[]>();
                foreach (var segItem in perfList.GroupBy(k => k.Segid))
                {
                    foreach (var perfItem in segItem.ToList())
                    {
                        if (perfItem.Easl_All == esalItem[0])
                        {
                            double[] d = new double[2];
                            d[0] = perfItem.Easl_All.ToD();
                            d[1] = perfItem.Pciave.ToD();
                            yList.Add(d);
                        }
                    }
                }

                series.Add(
                   new
                   {
                       type = "scatter",
					   showInLegend=false,
                       name = string.Format("累计交通量{0}", esalItem[0]),
                       marker = new { radius = 4 },
                       data = yList.ToArray()
                   }
               );
            }      

            return series;                
        }

        public dynamic GetModelDetail(string modelId)
        {
            ISthpms1Dao dao=this.Scene.Dal.Sthpms1;
            Dm_Modelgroup model = dao.SingleById<Dm_Modelgroup>(modelId);
            if (model == null) throw new Exception("该模型不存在-"+modelId);
            List<Dm_Histperf> perfList=dao.Select<Dm_Histperf>(p=>p.Modelgroup_Id==modelId);

            dynamic data = new System.Dynamic.ExpandoObject();
            data.Modelgroup_Id = modelId;
            data.ModelName =GetModelName(model);

            if (perfList.Count > 0)
            {
                data.BeginYear = perfList.Min(p=>p.Perfyear);
                data.EndYear = perfList.Max(p => p.Perfyear);       
            }
            data.PciCount = perfList.Count;
             return data;
        }

        private string GetModelName(Dm_Modelgroup model)
        {
            return  string.Format("{0}-{1}-{2}-{3}-{4}-({5}~{6})",
                ((RegressionIndicatorsEnum)model.Indextype_Dictid).GetEnumDescription(),
                ((PavementTypeEnum)model.Pvmttype_Dictid).GetEnumDescription(),
                ((RoadBasicTypeEnum)model.Basictype_Dictid).GetEnumDescription(),
                ((ModelFormEnum)model.Modelmode_Dictid).GetEnumDescription(),
                ((MainTypeEnum)model.Modeltype_Dictid).GetEnumDescription(),
                    model.Thick_Min,
                    model.Thick_Max
                );
        }

        public void CalcReturn(string modelId,int modelMode,int beginYear,int endYear) {
            ISthpms1Dao dao = this.Scene.Dal.Sthpms1;

            if (ModelFormEnum.M821.GetEnumValue() == modelMode)
            {
                if (beginYear > endYear) throw new Exception("结束年大于起始年!");

                Dm_Modelgroup model = dao.SingleById<Dm_Modelgroup>(modelId);
                if (model == null) throw new Exception("该模型不存在-" + modelId);
                Dm_Modelgroup_History history = ObjectMapperManager.DefaultInstance.GetMapper<IDm_Modelgroup, Dm_Modelgroup_History>().Map(model);

                List<Dm_Histperf> perfList = dao.Select<Dm_Histperf>(p => p.Modelgroup_Id == modelId &&
                    (p.Perfyear >= beginYear && p.Perfyear <= endYear));
       
                short maxYear=0;
                Dictionary<int,Perf> dict=new Dictionary<int,Perf>();
                foreach (var perf in perfList.GroupBy(p=>p.Segid))
                {
                    int openYear = 0;///通车时间
                    B_Invntory inv = dao.SingleById<B_Invntory>(perf.Key);
                    if (inv == null)
                    {
                        B_Invntory_History inv1 = dao.SingleById<B_Invntory_History>(perf.Key);
                        openYear = inv1.Begindate.Value.Year;
                    }
                    else {
                        openYear = inv.Begindate.Value.Year;
                    }
                    if (openYear == 0) throw new Exception("该路段信息没有找到-"+perf.Key);
                    List<Dm_Esalage> ageList=dao.Select<Dm_Esalage>(p=>p.Segid==perf.Key);
                    if(ageList.Count==0) throw new Exception("该路段的路龄与轴载关系没有找到-"+perf.Key);

                    foreach (var item in perf.ToList())
                    {
                        int i = item.Perfyear - openYear;                      
                        Dm_Esalage e=ageList.SingleOrDefault(p=>p.Perfyear==i);
                        if(e==null)continue;

                        if (!dict.ContainsKey(i))
                        {
                            dict.Add(i, new Perf(i));
                        }

                        dict[i].Easl.Add(e.Easl??0);
                        dict[i].Pci.Add(item.Pciave??0);
                        if(item.Perfyear>maxYear)maxYear=item.Perfyear;
                    }
                }
                if (dict.Count <2) throw new Exception("该路段的路龄累计轴载数据计算要有两年以上数据!");


                Dictionary<double, double> dictAvg = new Dictionary<double, double>();
                foreach (var item in dict)
                {
                    Perf p=item.Value;
                    dictAvg.Add(p.Easl.Average(), p.Pci.Average());
                }
                double avgX = dictAvg.Keys.Average();
                double avgY = dictAvg.Values.Average();

                double b1= 0;
                double b2 = 0;
                double r1=0;
                double r2=0;
                double r3=0;
                foreach (var item in dictAvg)
                {
                    b1 +=(item.Key - avgX) * (item.Value - avgY);
                    b2 +=Math.Pow((item.Key - avgX), 2);

                    r1+=(item.Key-avgX)* (item.Value - avgY) ;
                    r2+= Math.Pow((item.Key - avgX), 2);
                    r3+=Math.Pow((item.Value - avgY), 2);
                }
                double b=b1/b2;
                double a = avgY - b * avgX;
                double n=dictAvg.Count - 1;

                model.Formulacoeff1 = b;
                model.Formulacoeff2 = a;
                model.Calibrated = DateTime.Now;
                model.Lastyear = maxYear;
                model.Regbegin =Convert.ToInt16(beginYear);
                model.Regend = Convert.ToInt16(endYear);
                model.Coeff = (r1 / n) / (Math.Sqrt(r2/n) * Math.Sqrt(r3/n));


                dao.Save(model);
                dao.Save(history);
            }

        }
    }

    class Perf
    {
        public Perf(int age)
        {
            Age=age + 1;//默认路龄要在0基础上加1
        }
        public int Age;//路龄
        public List<double> Easl = new List<double>();//第i年份的累计当量轴载（百万次);
        public List<double> Pci = new List<double>();//第i年的路面性能指标值;
    }
}
